/*
 * Copyright (c) United Binary LLC.  All rights reserved.
 * 
 * This code is licensed under the MIT License
 * 
 * SEE: http://harnessit.codeplex.com/license
 * 
 */
using System;
using System.Collections;
using System.Drawing;
using System.Text;

using UnitedBinary.Core.Windows.Forms;

using UnitedBinary.UnitTests.Framework;
using UnitedBinary.HarnessIt.SharedTypes;
using UnitedBinary.UnitTests.Framework.TestItems;
using System.Collections.Generic;

namespace UnitedBinary.HarnessIt
{
	#region ReportPerformanceDetails class
	internal class ReportPerformanceDetails
	{
		/// <summary>
		///		The time required to run the tests.
		/// </summary>
		internal double runningTime;

		internal double executionTime;

		/// <summary>
		///		Number of assemblies in the project.
		/// </summary>
		internal int AssemblyCount = 0;

		/// <summary>
		///		Number of classes in the assemblies.
		/// </summary>
		internal int ClassCount = 0;

		/// <summary>
		///		Number of methods in the classes.
		/// </summary>
		internal int MethodCount = 0;

		/// <summary>
		///		Number of test classes (UBTestClass classes).
		/// </summary>
		internal int TestClassCount = 0;

		/// <summary>
		///		Number of test methods (UBTestMethod methods).
		/// </summary>
		internal int TestMethodCount = 0;

		/// <summary>
		///		A summary of the test results.
		/// </summary>
		internal TestMethodRecord TotalRecord;

		internal ReportPerformanceDetails()
		{
			TotalRecord = new TestMethodRecord();
			runningTime = 0.0;
			executionTime = 0.0;
		}
	}
	#endregion

	/// <summary>
	///		ReportFormatter is a class to generate and format reports
	///		on unit test projects, assemblies, classes, and methods.
	/// </summary>
	internal class ReportFormatter
	{
		#region Member Variables

		private static System.Drawing.Font font16B	= new System.Drawing.Font("Tahoma", 16);
		private static System.Drawing.Font font10	= new System.Drawing.Font("Tahoma", 10);
		private static System.Drawing.Font font10B	= new System.Drawing.Font("Tahoma", 10, FontStyle.Bold);
		private static System.Drawing.Font font10U	= new System.Drawing.Font("Tahoma", 10, FontStyle.Underline);
		private static System.Drawing.Font font8	= new System.Drawing.Font("Tahoma", 8);
		private static System.Drawing.Font font8U	= new System.Drawing.Font("Tahoma", 8, FontStyle.Underline);
		private static System.Drawing.Font font8B	= new System.Drawing.Font("Tahoma", 8, FontStyle.Bold);

		#endregion

		#region Construction
		/// <summary>
		///		Default constructor.
		/// </summary>
		internal ReportFormatter()
		{
		}
		#endregion

		#region Generate All Test Report Summary
		/// <summary>
		///		ReportTests generates the summary for all the reports. 
		/// </summary>
		internal static void ReportTests(ReportPerformanceDetails perf, TestProject proj, RichTextComposition rtComp)
		{
			rtComp.Font = ReportFormatter.font16B;
			rtComp.AddLine("Project: " + proj.Name);
			
			rtComp.Font = ReportFormatter.font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.AddLine("");

			rtComp.Font = ReportFormatter.font10U;
			rtComp.AddLine("Test Results");
			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font10;

			float percent = 100 * perf.TotalRecord.Successes / (float)perf.TotalRecord.TestCount;
			string passed = "PASSED:\t\t" + perf.TotalRecord.Successes;
			if (perf.TotalRecord.TestCount > 0)
			{
				passed += "\t(" + percent.ToString("f1") + "%)";
			}
			RichTextString passedRich = new RichTextString();
			passedRich.Font = ReportFormatter.font10;
			passedRich.Text = passed;
			passedRich.R = 0;
			passedRich.G = 0;
			if (perf.TotalRecord.Failures == 0 && perf.TotalRecord.Successes > 0)
			{
				passedRich.B = 255;	
			}
			else
			{
				passedRich.B = 0;	
			}
			rtComp.AddLine(passedRich);

			percent = 100 * perf.TotalRecord.Failures / (float)perf.TotalRecord.TestCount;
			string failed = "FAILED:\t\t\t" + perf.TotalRecord.Failures;
			if (perf.TotalRecord.TestCount > 0)
			{
				failed += "\t(" + percent.ToString("f1") + "%)";
			}
			RichTextString failedRich = new RichTextString();
			failedRich.Text = failed;
			failedRich.Font = ReportFormatter.font10;
			if (perf.TotalRecord.Failures > 0)
			{
				failedRich.R = 255;
			}
			else
			{
				failedRich.R = 0;
			}
			failedRich.G = 0;
			failedRich.B = 0;
			rtComp.AddLine(failedRich);

			RichTextString totalRich = new RichTextString();
			totalRich.Text = "TOTAL:\t\t\t" + perf.TotalRecord.TestCount;
			totalRich.Font = ReportFormatter.font10;
			rtComp.AddLine(totalRich);

			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font10U;
			rtComp.AddLine("Project Overview");
			rtComp.Font = ReportFormatter.font10;
			rtComp.AddLine("");
			rtComp.AddLine("Assembly Count:\t" + perf.AssemblyCount);
			rtComp.AddLine("Class Count:\t\t" + perf.ClassCount);
			rtComp.AddLine("Method Count:\t\t" + perf.MethodCount);
			rtComp.AddLine("");
			float p1 = 100 * perf.TestClassCount / (float)perf.ClassCount;
			float p2 = 100 * perf.TestMethodCount / (float)perf.MethodCount;
			
			rtComp.Add("Test Class Count:\t"+perf.TestClassCount);
			if (perf.ClassCount > 0)
			{
				rtComp.AddLine("\t(" + p1.ToString("f1") + "%)");
			}
			else
			{
				rtComp.AddLine("");
			}
			
			rtComp.Add("Test Method Count:\t" + perf.TestMethodCount);
			if (perf.MethodCount > 0)
			{
				rtComp.AddLine("\t(" + p2.ToString("f1") + "%)");
			}
			else
			{
				rtComp.AddLine("");
			}
			
			rtComp.AddLine("");
			rtComp.AddLine("Tests Performed:\t" + perf.TotalRecord.TestCount);
			rtComp.AddLine("");
			rtComp.AddLine("Elapsed Time:\t\t" + perf.runningTime.ToString("F3") + " seconds.");
			rtComp.AddLine("Execution Time:\t\t" + perf.executionTime.ToString("F3") + " seconds.");
		}
		#endregion

		#region Generate Assembly Summary
		/// <summary>
		///		ReportTests(Assembly A) generates a report for the tests in assembly A.
		/// </summary>
		/// <param name="A">Assembly to generate a report about.</param>
		internal static void ReportTests(Assembly A, TestProject proj, RichTextComposition rtComp,
			HarnessItTraceListener traceListener)
		{
			rtComp.Font = ReportFormatter.font16B;
			rtComp.AddLine("Project: " + proj.Name);
			
			rtComp.Font = ReportFormatter.font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.AddLine("");

			rtComp.Font = ReportFormatter.font10B;
			rtComp.AddLine("Test results for assembly " + A.Name);
			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font10;
			
			if (A.ContainsTests)
			{
				float percent = 100 * A.TestRecord.Successes / (float)A.TestRecord.TestCount;
				string passed = "PASSED:\t\t" + A.TestRecord.Successes;
				if (A.TestRecord.TestCount > 0)
				{
					passed += "\t(" + percent.ToString("f1") + "%)";
				}
				RichTextString passedRich = new RichTextString();
				passedRich.Font = ReportFormatter.font10;
				passedRich.Text = passed;
				if (A.TestRecord.Failures == 0 && A.TestRecord.Successes > 0)
				{
					passedRich.B = 255;
				}
				rtComp.AddLine(passedRich);

				percent = 100 * A.TestRecord.Failures / (float)A.TestRecord.TestCount;
				string failed = "FAILED:\t\t\t" + A.TestRecord.Failures;
				if (A.TestRecord.TestCount > 0)
				{
					failed += "\t(" + percent.ToString("f1") + "%)";
				}
				RichTextString failedRich = new RichTextString();
				failedRich.Text = failed;
				failedRich.Font = ReportFormatter.font10;
				if (A.TestRecord.Failures > 0)
				{
					failedRich.R = 255;
				}
				rtComp.AddLine(failedRich);
				rtComp.AddLine("TOTAL:\t\t\t" + A.TestRecord.TestCount);

				rtComp.AddLine("");
				rtComp.Font = ReportFormatter.font10B;
				rtComp.AddLine("Assembly Description");
				rtComp.Font = ReportFormatter.font10;
				if (A.Description == null || A.Description.Length == 0)
				{
					rtComp.AddLine("None: Use TestAssembly attribute to specify a description.");
				}
				else
				{
					rtComp.AddLine(A.Description);
				}
				
				if (!A.TestRecord.HasRun)
				{
					rtComp.AddLine("");
					rtComp.AddLine("No tests have been preformed on this assembly.");
				}
			}
			else
			{
				rtComp.AddLine("");
				rtComp.AddLine("THIS ASSEMBLY DOES NOT CONTAIN TEST METHODS.");
			}
			rtComp.AddLine("");

			rtComp.Font = ReportFormatter.font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.Font = ReportFormatter.font10B;
			rtComp.AddLine("Additional Assembly Information");
			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font10;

			rtComp.AddLine("Class Count:\t\t" + A.ClassCount);
			rtComp.AddLine("Tests Performed:\t" + A.TestRecord.TestCount);
			rtComp.AddLine("");
			rtComp.AddLine("Execution Time:\t\t" + A.RunningTime.ToString("F3") + " seconds.");
			rtComp.AddLine("");

			rtComp.AddLine("Assembly Path Name");
			rtComp.Font = ReportFormatter.font8;
			rtComp.AddLine(A.FullPathName);
			rtComp.Font = ReportFormatter.font10;

			if (!A.TestRecord.HasRun)
			{
				return;
			}

			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.Font = ReportFormatter.font10B;
			rtComp.AddLine("Test Result Details");
			rtComp.AddLine("");
			rtComp.Font = ReportFormatter.font10;

			Class [] localClasses = A.Classes;

			//
			// Generate the FAILURES block:
			//
			rtComp.AddLine(new RichTextString("Test Output (failures only):", Color.Black, font10B));
			rtComp.AddLine("");

			bool generatedOutput = false;
			foreach (Class c in localClasses)
			{
				if (c.TestRecord.Failures > 0)
				{
					generatedOutput = true;

					StringBuilder sb = new StringBuilder();
					sb.Append("Class ");
					sb.Append(c.Name);
					rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));

					Method [] localMethods = c.Methods;
					int methodLength = localMethods.Length;

					for (int k=0; k < methodLength; k++)
					{
						Method m = localMethods[k];
						TestMethodRecord tmr = m.TestRecord;
						int toCount = tmr.TestObjectCount;
						int testCount = 0;

						if (tmr.Failures > 0)
						{
							sb = new StringBuilder();
							sb.Append("Method ");
							sb.Append(m.Name);
							rtComp.Add(new RichTextString(sb.ToString(), Color.Black, font8U));

							sb = new StringBuilder();
							sb.Append(" (");
							sb.Append(tmr.Failures);
							if (tmr.Failures > 1)
							{
								sb.Append(" failures):");
							}
							else
							{
								sb.Append(" failure):");
							}
							rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));

							for(int i=0; i < toCount; i++)
							{
								TestObject o = tmr.GetResult(i);
								if (o.TestObjectType == TestObjectTypes.TestResult)
								{
									testCount++;
									TestResult tr = (TestResult)o;
									if (!tr.Success)
									{
										sb = new StringBuilder();
										sb.Append("Failed test ");
										sb.Append(testCount);
										sb.Append(": ");
										sb.Append(tr.Description);

										rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
									}
								}
							}
							//rtComp.AddLine("");	
						}
					}
					rtComp.AddLine("");	
				}
			}
			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No failures.", Color.Black, font8));
				rtComp.AddLine("");
			}

			//
			// Generate the All output block:
			//
			rtComp.AddLine(new RichTextString("Test Output (all):", Color.Black, font10B));
			rtComp.AddLine("");

			generatedOutput = false;
			bool classLineAdded = false;
			foreach (Class c in localClasses)
			{
				Method [] localMethods = c.Methods;
				int methodLength = localMethods.Length;
				classLineAdded = false;
				
				for (int k=0; k < methodLength; k++)
				{
					Method m = localMethods[k];
					TestMethodRecord tmr = m.TestRecord;

					int toCount = tmr.TestObjectCount;
					int testCount = 0;

					if (toCount > 0)
					{
						generatedOutput = true;

						StringBuilder sb;
						if (!classLineAdded)
						{
							sb = new StringBuilder();
							sb.Append("Class ");
							sb.Append(c.Name);
							sb.Append(":");
							rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));

							classLineAdded = true;
						}

						sb = new StringBuilder();
						sb.Append("Method ");
						sb.Append(m.Name);
						sb.Append(":");
						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));
					}
	
					testCount = 0;
					for(int i=0; i < toCount; i++)
					{
						TestObject o = tmr.GetResult(i);
						if (o.TestObjectType == TestObjectTypes.TestResult)
						{
							testCount++;
							TestResult tr = (TestResult)o;
							StringBuilder sb = new StringBuilder();
							if (!tr.Success)
							{
								sb.Append("FAILED test ");
							}
							else
							{
								sb.Append("Passed test ");
							}
					
							sb.Append(testCount);
							sb.Append(": ");
							sb.Append(tr.Description);
					
							rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
						}
						else if (o.TestObjectType == TestObjectTypes.TestComment)
						{
							TestComment tc = (TestComment)o;

							StringBuilder sb = new StringBuilder();
							sb = new StringBuilder();
							sb.Append("Comment: ");
							sb.Append(tc.Comment);
										
							rtComp.AddLine(new RichTextString(sb.ToString(), Color.Green, font8));
						}
					}
//
//					if (toCount > 0)
//					{
//						rtComp.AddLine("");
//					}
				}
				if (classLineAdded)
				{
					rtComp.AddLine("");
				}
			}
			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No test output.", Color.Black, font8));
				rtComp.AddLine("");
			}

			//
			// Generate the Trace output block:
			//
			rtComp.AddLine(new RichTextString("Trace Output:", Color.Black, font10B));
			rtComp.AddLine("");
			
			generatedOutput = false;
			foreach (Class c in localClasses)
			{
				Method [] localMethods = c.Methods;
				int methodLength = localMethods.Length;
				classLineAdded = false;

				for (int k=0; k < methodLength; k++)
				{
					Method m = localMethods[k];
					TestMethodRecord tmr = m.TestRecord;

					int toCount = tmr.TestObjectCount;

					AssociatedTestTracing trace;
					trace = traceListener.GetAssociationByName(m.ClassName + "." + m.Name);
					if (trace != null)
					{
						string [] messages = trace.TraceMessages;
						if (messages != null)
						{
							generatedOutput = true;

							StringBuilder sb;
							if (!classLineAdded)
							{
								sb = new StringBuilder();
								sb.Append("Class ");
								sb.Append(c.Name);
								sb.Append(":");
								rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));

								classLineAdded = true;
							}

							sb = new StringBuilder();
							sb.Append("Method ");
							sb.Append(m.Name);
							sb.Append(":");
							rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));

							int length = messages.Length;
							for (int i=0; i < length; i++)
							{
								sb = new StringBuilder();
								sb.Append("Trace message ");
								sb.Append((i+1));
								sb.Append(": ");
								sb.Append(messages[i]);

								rtComp.AddLine(new RichTextString(sb.ToString(), Color.DarkGray, font8));
							}
						}
						//rtComp.AddLine("");
					}
				}
				if (classLineAdded)
				{
					rtComp.AddLine("");
				}
			}
			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No trace output.", Color.Black, font8));
				rtComp.AddLine("");
			}
		}

		#endregion

		#region Generate Class Summary
		/// <summary>
		///		ReportTests(Class C) generates a report for the tests in the class C.
		/// </summary>
		/// <param name="C">The class to generate a report on.</param>
		internal static void ReportTests(Class C, TestProject proj, RichTextComposition rtComp,
			HarnessItTraceListener traceListener)
		{
			rtComp.Font = ReportFormatter.font16B;
			rtComp.AddLine("Project: " + proj.Name);
			
			rtComp.Font = font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.AddLine("");

			rtComp.Font = font10B;
			rtComp.AddLine("Test results for class " + C.Name);
			rtComp.AddLine("");
			rtComp.Font = font10;
			
			if (C.ContainsTests)
			{
				float percent = 100 * C.TestRecord.Successes / (float)C.TestRecord.TestCount;
				string passed = "PASSED:\t\t" + C.TestRecord.Successes;
				if (C.TestRecord.TestCount > 0)
				{
					passed += "\t("+percent.ToString("f1") + "%)";
				}
				RichTextString passedRich = new RichTextString();
				passedRich.Font = font10;
				passedRich.Text = passed;
				if (C.TestRecord.Failures == 0 && C.TestRecord.Successes > 0)
				{
					passedRich.B = 255;
				}
				rtComp.AddLine(passedRich);

				percent = 100 * C.TestRecord.Failures / (float)C.TestRecord.TestCount;
				string failed = "FAILED:\t\t\t" + C.TestRecord.Failures;
				if (C.TestRecord.TestCount > 0)
				{
					failed += "\t(" + percent.ToString("f1") + "%)";
				}
				RichTextString failedRich = new RichTextString();
				failedRich.Text = failed;
				failedRich.Font = font10;
				if (C.TestRecord.Failures > 0)
				{
					failedRich.R = 255;
				}
				rtComp.AddLine(failedRich);
				rtComp.AddLine("TOTAL:\t\t\t" + C.TestRecord.TestCount);
				rtComp.AddLine("");
				rtComp.AddLine("Execution Time:\t\t" + C.RunningTime.ToString("F3") + " seconds.");
				
				if (!C.TestRecord.HasRun)
				{
					rtComp.AddLine("");
					rtComp.AddLine("No tests have been performed on this class.");
				}
			}
			else
			{
				rtComp.AddLine("");
				rtComp.AddLine("THIS CLASS DOES NOT CONTAIN TEST METHODS.");
				return;
			}

			rtComp.AddLine("");
			rtComp.Font = font10B;
			rtComp.AddLine("Class Description");
			rtComp.Font = font8;
			if (C.Description == null || C.Description.Length == 0)
			{
				rtComp.AddLine("None: Use TestClass attribute to specify a description.");
			}
			else
			{
				rtComp.AddLine(C.Description);
			}

			if (!C.TestRecord.HasRun)
			{
				return;
			}

			rtComp.AddLine("");
			rtComp.Font = font8;
			rtComp.AddLine("____________________________________________________________");
			rtComp.Font = font10B;
			rtComp.AddLine("Test Result Details");
			rtComp.AddLine("");
			rtComp.Font = font8;

			Method [] localMethods = C.Methods;
			int methodLength = localMethods.Length;
			
			//
			// Generate the FAILURES block:
			//
			rtComp.AddLine(new RichTextString("Test Output (failures only):", Color.Black, font10B));
			rtComp.AddLine("");

			bool generatedOutput = false;
			for (int k=0; k < methodLength; k++)
			{
				Method m = localMethods[k];
				TestMethodRecord tmr = m.TestRecord;
				int toCount = tmr.TestObjectCount;
				int testCount = 0;

				if (tmr.Failures > 0)
				{
					generatedOutput = true;

					StringBuilder sb = new StringBuilder();
					sb.Append("Method ");
					sb.Append(m.Name);
					rtComp.Add(new RichTextString(sb.ToString(), Color.Black, font8U));

					sb = new StringBuilder();
					sb.Append(" (");
					sb.Append(tmr.Failures);
					if (tmr.Failures > 1)
					{
						sb.Append(" failures):");
					}
					else
					{
						sb.Append(" failure):");
					}
					rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));

					for(int i=0; i < toCount; i++)
					{
						TestObject o = tmr.GetResult(i);
						if (o.TestObjectType == TestObjectTypes.TestResult)
						{
							testCount++;
							TestResult tr = (TestResult)o;
							if (!tr.Success)
							{
								sb = new StringBuilder();
								sb.Append("Failed test ");
								sb.Append(testCount);
								sb.Append(": ");
								sb.Append(tr.Description);

								rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
							}
						}
					}

					rtComp.AddLine("");	
				}
			}

			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No failures.", Color.Black, font8));
				rtComp.AddLine("");
			}

			//
			// Generate the All output block:
			//
			rtComp.AddLine(new RichTextString("Test Output (all):", Color.Black, font10B));
			rtComp.AddLine("");

			generatedOutput = false;
			for (int k=0; k < methodLength; k++)
			{
				Method m = localMethods[k];
				TestMethodRecord tmr = m.TestRecord;

				int toCount = tmr.TestObjectCount;
				int testCount = 0;

				if (toCount > 0)
				{
					generatedOutput = true;

					StringBuilder sb = new StringBuilder();
					sb.Append("Method ");
					sb.Append(m.Name);
					sb.Append(":");
					rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));
				}
	
				testCount = 0;
				for(int i=0; i < toCount; i++)
				{
					TestObject o = tmr.GetResult(i);
					if (o.TestObjectType == TestObjectTypes.TestResult)
					{
						testCount++;
						TestResult tr = (TestResult)o;
						StringBuilder sb = new StringBuilder();
						if (!tr.Success)
						{
							sb.Append("FAILED test ");
						}
						else
						{
							sb.Append("Passed test ");
						}
					
						sb.Append(testCount);
						sb.Append(": ");
						sb.Append(tr.Description);
					
						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
					}
					else if (o.TestObjectType == TestObjectTypes.TestComment)
					{
						TestComment tc = (TestComment)o;

						StringBuilder sb = new StringBuilder();
						sb = new StringBuilder();
						sb.Append("Comment: ");
						sb.Append(tc.Comment);
										
						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Green, font8));
					}
				}

				if (toCount > 0)
				{
					rtComp.AddLine("");
				}
			}
			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No test output.", Color.Black, font8));
				rtComp.AddLine("");
			}

			//
			// Generate the Trace output block:
			//
			rtComp.AddLine(new RichTextString("Trace Output:", Color.Black, font10B));
			rtComp.AddLine("");

			generatedOutput = false;
			for (int k=0; k < methodLength; k++)
			{
				Method m = localMethods[k];
				TestMethodRecord tmr = m.TestRecord;

				int toCount = tmr.TestObjectCount;

				AssociatedTestTracing trace;
				trace = traceListener.GetAssociationByName(m.ClassName + "." + m.Name);
				if (trace != null)
				{
					string [] messages = trace.TraceMessages;
					if (messages != null)
					{
						generatedOutput = true;

						StringBuilder sb = new StringBuilder();
						sb.Append("Method ");
						sb.Append(m.Name);
						sb.Append(":");
						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8U));

						int length = messages.Length;
						for (int i=0; i < length; i++)
						{
							sb = new StringBuilder();
							sb.Append("Trace message ");
							sb.Append((i+1));
							sb.Append(": ");
							sb.Append(messages[i]);

							rtComp.AddLine(new RichTextString(sb.ToString(), Color.DarkGray, font8));
						}
					}

					rtComp.AddLine("");
				}
			}
			if (!generatedOutput)
			{
				rtComp.AddLine(new RichTextString("No trace output.", Color.Black, font8));
				rtComp.AddLine("");
			}
		}
		#endregion

		#region Generate Method Summary
		/// <summary>
		///		ReportTests(Method m) generates a report for the method m.
		/// </summary>
		/// <param name="m">The method to generate a report about.</param>
	//	internal static void ReportTests(Method m, TestProject proj, RichTextComposition rtComp,
	//		HarnessItTraceListener traceListener)
	//	{
	//		rtComp.Font = font16B;
	//		rtComp.AddLine("Project: " + proj.Name);
	//		
	//		rtComp.Font = font8;
	//		rtComp.AddLine("____________________________________________________________");
	//		rtComp.AddLine("");

	//		rtComp.Font = font10B;
	//		rtComp.AddLine("Test results for method " + m.Name);
	//		rtComp.AddLine("");
	//		rtComp.Font = font10;
	//		
	//		float percent = 100 * m.TestRecord.Successes / (float)m.TestRecord.TestCount;
	//		string passed = "PASSED:\t\t" + m.TestRecord.Successes;
	//		if (m.TestRecord.TestCount > 0)
	//		{
	//			passed += "\t(" + percent.ToString("f1") + "%)";
	//		}
	//		RichTextString passedRich = new RichTextString();
	//		passedRich.Font = font10;
	//		passedRich.Text = passed;
	//		if (m.TestRecord.Failures == 0 && m.TestRecord.Successes > 0)
	//		{
	//			passedRich.B = 255;
	//		}
	//		rtComp.AddLine(passedRich);

	//		percent = 100 * m.TestRecord.Failures / (float)m.TestRecord.TestCount;
	//		string failed = "FAILED:\t\t\t" + m.TestRecord.Failures;
	//		if (m.TestRecord.TestCount > 0)
	//		{
	//			failed += "\t(" + percent.ToString("f1") + "%)";
	//		}
	//		RichTextString failedRich = new RichTextString();
	//		failedRich.Text = failed;
	//		failedRich.Font = font10;
	//		if (m.TestRecord.Failures > 0)
	//		{
	//			failedRich.R = 255;
	//		}
	//		rtComp.AddLine(failedRich);
	//		rtComp.AddLine("TOTAL:\t\t\t" + m.TestRecord.TestCount);
	//		rtComp.AddLine("");
	//		rtComp.AddLine("Execution Time:\t\t" + m.RunningTime.ToString("F3") + " seconds.");

	//		if (!m.HasRun)
	//		{
	//			rtComp.AddLine("");
	//			rtComp.AddLine("This test method has not been executed.");
	//		}

	//		rtComp.AddLine("");
	//		rtComp.Font = font10B;
	//		rtComp.AddLine("Method Description");
	//		rtComp.Font = font8;
	//		if (m.Description == null || m.Description.Length == 0)
	//		{
	//			rtComp.AddLine("None.");
	//		}
	//		else
	//		{
	//			rtComp.AddLine(m.Description);
	//		}

	//		if (!m.HasRun)
	//		{
	//			return;
	//		}

	//		rtComp.AddLine("");
	//		rtComp.Font = font8;
	//		rtComp.AddLine("____________________________________________________________");
	//		rtComp.Font = font10B;
	//		rtComp.AddLine("Test Result Details");
	//		rtComp.AddLine("");
	//		rtComp.Font = font10;

	//		//
	//		// Generate the FAILURES block:
	//		//
	//		rtComp.AddLine(new RichTextString("Test Output (failures only):", Color.Black, font10B));

	//		TestMethodRecord tmr = m.TestRecord;
	//		int toCount = tmr.TestObjectCount;
	//		int testCount = 0;
	//		if (tmr.Failures == 0)
	//		{
	//			rtComp.AddLine("");
	//			rtComp.AddLine(new RichTextString("No failures.", Color.Black, font8));
	//			rtComp.AddLine("");
	//		}
	//		else //if (tmr.Failures > 0)
	//		{
	//			rtComp.AddLine("");
	//			if (tmr.Failures > 1)
	//			{
	//				rtComp.AddLine(new RichTextString(tmr.Failures + " failures occurred.", Color.Red, font8));
	//			}
	//			else
	//			{
	//				rtComp.AddLine(new RichTextString(tmr.Failures + " failure occurred.", Color.Red, font8));
	//			}
	//			rtComp.AddLine("");

	//			for(int i=0; i < toCount; i++)
	//			{
	//				TestObject o = tmr.GetResult(i);
	//				if (o.TestObjectType == TestObjectTypes.TestResult)
	//				{
	//					testCount++;
	//					TestResult tr = (TestResult)o;
	//					if (!tr.Success)
	//					{
	//						StringBuilder sb = new StringBuilder();
	//						sb.Append("Failed test ");
	//						sb.Append(testCount);
	//						sb.Append(": ");
	//						sb.Append(tr.Description);

	//						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
	//					}
	//				}
	//			}

	//			rtComp.AddLine("");	
	//		}

	//		//
	//		// Generate the All output block:
	//		//
	//		rtComp.AddLine(new RichTextString("Test Output (all):", Color.Black, font10B));
	//		rtComp.AddLine("");

	//		if (toCount == 0)
	//		{
	//			rtComp.AddLine(new RichTextString("No test output.", Color.Black, font8));
	//		}
	//
	//		testCount = 0;
	//		for(int i=0; i < toCount; i++)
	//		{
	//			TestObject o = tmr.GetResult(i);
	//			if (o.TestObjectType == TestObjectTypes.TestResult)
	//			{
	//				testCount++;
	//				TestResult tr = (TestResult)o;
	//				StringBuilder sb = new StringBuilder();
	//				if (!tr.Success)
	//				{
	//					sb.Append("FAILED test ");
	//				}
	//				else
	//				{
	//					sb.Append("Passed test ");
	//				}
	//				
	//				sb.Append(testCount);
	//				sb.Append(": ");
 //                   sb.Append(tr.Description);
	//				
	//				rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
	//			}
	//			else if (o.TestObjectType == TestObjectTypes.TestComment)
	//			{
	//				TestComment tc = (TestComment)o;

	//				StringBuilder sb = new StringBuilder();
	//				sb = new StringBuilder();
	//				sb.Append("Comment: ");
	//				sb.Append(tc.Comment);
	//									
	//				rtComp.AddLine(new RichTextString(sb.ToString(), Color.Green, font8));
	//			}
	//		}
	//		rtComp.AddLine("");

	//		//
	//		// Generate the Trace output block:
	//		//
	//		rtComp.AddLine(new RichTextString("Trace Output:", Color.Black, font10B));
	//		rtComp.AddLine("");

	//		AssociatedTestTracing trace;
 //           trace = traceListener.GetAssociationByName(m.ClassName + "." + m.Name);
	//		if (trace == null)
	//		{
	//			rtComp.AddLine(new RichTextString("No Trace output associated with this method.", Color.Black, font8));
	//		}
	//		else
	//		{
	//			string [] messages = trace.TraceMessages;
	//			if (messages == null)
	//			{
	//				rtComp.AddLine(new RichTextString("No Trace output associated with this method.", Color.Black, font8));
	//			}
	//			else
	//			{
	//				int length = messages.Length;
	//				for (int i=0; i < length; i++)
	//				{
	//					StringBuilder sb = new StringBuilder();
	//					sb.Append("Trace message ");
	//					sb.Append((i+1));
	//					sb.Append(": ");
	//					sb.Append(messages[i]);

	//					rtComp.AddLine(new RichTextString(sb.ToString(), Color.DarkGray, font8));
	//				}
	//			}
	//		}

	//		rtComp.AddLine("");
	//	}


		internal static void ReportTests(IMethod m,RichTextComposition rtComp)
		{
			rtComp.SuspendRendering = true;
			try
			{
				rtComp.Font = font10B;
				rtComp.AddLine("Test results for method " + m.Name);
				rtComp.AddLine("");
				rtComp.Font = font10;

				float percent = 100 * m.TestRecord.Successes / (float)m.TestRecord.TestCount;
				string passed = "PASSED:\t\t" + m.TestRecord.Successes;
				if (m.TestRecord.TestCount > 0)
				{
					passed += "\t(" + percent.ToString("f1") + "%)";
				}
				RichTextString passedRich = new RichTextString();
				passedRich.Font = font10;
				passedRich.Text = passed;
				if (m.TestRecord.Failures == 0 && m.TestRecord.Successes > 0)
				{
					passedRich.B = 255;
				}
				rtComp.AddLine(passedRich);

				percent = 100 * m.TestRecord.Failures / (float)m.TestRecord.TestCount;
				string failed = "FAILED:\t\t\t" + m.TestRecord.Failures;
				if (m.TestRecord.TestCount > 0)
				{
					failed += "\t(" + percent.ToString("f1") + "%)";
				}
				RichTextString failedRich = new RichTextString();
				failedRich.Text = failed;
				failedRich.Font = font10;
				if (m.TestRecord.Failures > 0)
				{
					failedRich.R = 255;
				}
				rtComp.AddLine(failedRich);
				rtComp.AddLine("TOTAL:\t\t\t" + m.TestRecord.TestCount);
				rtComp.AddLine("");
				rtComp.AddLine("Execution Time:\t\t" + m.RunningTime.ToString("F3") + " seconds.");

				if (!m.HasRun)
				{
					rtComp.AddLine("");
					rtComp.AddLine("This test method has not been executed.");
				}

				rtComp.AddLine("");
				rtComp.Font = font10B;
				rtComp.AddLine("Method Description");
				rtComp.Font = font8;
				if (m.Description == null || m.Description.Length == 0)
				{
					rtComp.AddLine("None.");
				}
				else
				{
					rtComp.AddLine(m.Description);
				}

				if (!m.HasRun)
				{
					return;
				}

				rtComp.AddLine("");
				rtComp.Font = font8;
				rtComp.AddLine("____________________________________________________________");
				rtComp.Font = font10B;
				rtComp.AddLine("Test Result Details");
				rtComp.AddLine("");
				rtComp.Font = font10;

				//
				// Generate the FAILURES block:
				//
				rtComp.AddLine(new RichTextString("Test Output (failures only):", Color.Black, font10B));

				TestMethodRecord tmr = m.TestRecord;
				int toCount = tmr.TestObjectCount;
				int testCount = 0;
				if (tmr.Failures == 0)
				{
					rtComp.AddLine("");
					rtComp.AddLine(new RichTextString("No failures.", Color.Black, font8));
					rtComp.AddLine("");
				}
				else //if (tmr.Failures > 0)
				{
					rtComp.AddLine("");
					if (tmr.Failures > 1)
					{
						rtComp.AddLine(new RichTextString(tmr.Failures + " failures occurred.", Color.Red, font8));
					}
					else
					{
						rtComp.AddLine(new RichTextString(tmr.Failures + " failure occurred.", Color.Red, font8));
					}
					rtComp.AddLine("");

					for (int i = 0; i < toCount; i++)
					{
						TestObject o = tmr.GetResult(i);
						if (o.TestObjectType == TestObjectTypes.TestResult)
						{
							testCount++;
							TestResult tr = (TestResult)o;
							if (!tr.Success)
							{
								StringBuilder sb = new StringBuilder();
								sb.Append("Failed test ");
								sb.Append(testCount);
								sb.Append(": ");
								sb.Append(tr.Description);

								rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
							}
						}
					}

					rtComp.AddLine("");
				}

				//
				// Generate the All output block:
				//
				rtComp.AddLine(new RichTextString("Test Output (all):", Color.Black, font10B));
				rtComp.AddLine("");

				if (toCount == 0)
				{
					rtComp.AddLine(new RichTextString("No test output.", Color.Black, font8));
				}

				testCount = 0;
				for (int i = 0; i < toCount; i++)
				{
					TestObject o = tmr.GetResult(i);
					if (o.TestObjectType == TestObjectTypes.TestResult)
					{
						testCount++;
						TestResult tr = (TestResult)o;
						StringBuilder sb = new StringBuilder();
						if (!tr.Success)
						{
							sb.Append("FAILED test ");
						}
						else
						{
							sb.Append("Passed test ");
						}

						sb.Append(testCount);
						sb.Append(": ");
						sb.Append(tr.Description);

						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Black, font8));
					}
					else if (o.TestObjectType == TestObjectTypes.TestComment)
					{
						TestComment tc = (TestComment)o;

						StringBuilder sb = new StringBuilder();
						sb.Append("Comment: ");
						sb.Append(tc.Comment);

						rtComp.AddLine(new RichTextString(sb.ToString(), Color.Green, font8));
					}
				}
				rtComp.AddLine("");
			}
			finally
			{
				rtComp.SuspendRendering = false;
			}
		}

		#endregion

		#region Generate Failures Summary
		internal static void ReportFailures(List<Assembly> Assemblies, TestProject proj, RichTextComposition rtComp)
		{
			RichTextString s;

			bool failures = false;
			int failCount = 0;
			int passCount = 0;
			ArrayList reportText = new ArrayList();
			TestMethodRecord tmr;
			TestResult tr;
			string msg;
			StringBuilder sb;

			foreach(Assembly A in Assemblies)
			{
				passCount += A.TestRecord.Successes;
				failCount += A.TestRecord.Failures;

				Class [] localClasses = A.Classes;
				foreach(Class C in localClasses)
				{
					if (C.TestRecord.Failures > 0)
					{
						reportText.Add(new RichTextString("\nFailures in class ", Color.Black, font8B));
						reportText.Add(new RichTextString(C.Name, Color.Red, font8B));
						reportText.Add(new RichTextString(":\n", Color.Black, font8B));
					
						Method [] methods = C.Methods;
						int mLength = methods.Length;
						for (int k=0; k < mLength; k++)
						{
							Method m = methods[k];
							if (m.TestRecord.Failures > 0)
							{
								sb = new StringBuilder();

								sb.Append("Failures in method ");
								sb.Append(m.Name);
								sb.Append(":\n");

								failures = true;
								reportText.Add(new RichTextString(sb.ToString(), Color.Black, font8U));
							
								tmr = m.TestRecord;
								int count = tmr.TestObjectCount;

								for (int i=0; i < count; i++)
								{
									TestObject to = tmr.GetResult(i);
									if (to.TestObjectType == TestObjectTypes.TestResult)
									{
										tr = (TestResult)to;
										if (!tr.Success)
										{
											sb = new StringBuilder();
											sb.Append("FAILED: ");
											sb.Append(tr.Description);
											sb.Append("\n");

											reportText.Add(new RichTextString(sb.ToString(), Color.Black, font8));
										}
									}
								}

								sb = new StringBuilder();
								sb.Append("Method execution time: ");
								sb.Append(m.RunningTime.ToString("F3"));
								sb.Append(" seconds.\n");

								reportText.Add(new RichTextString(sb.ToString(), Color.DarkGray, font8));
							}
						}
					}
				}
			}

			// Prefix the first line with a summary message about failures.
			if (failures)
			{
				msg = failCount + " failures occurred in project " + proj.Name + ".\n";
				s = new RichTextString(msg, Color.Black, font8B);
				reportText.Insert(0, s);
			}
			else if (passCount > 0)
			{
				msg = "All tests succeeded.\n";
				s = new RichTextString(msg, Color.Black, font8B);
				reportText.Insert(0, s);
			}
			else
			{
				msg = "No tests have been run.\n";
				s = new RichTextString(msg, Color.Black, font8B);
				reportText.Insert(0, s);
			}

			foreach(RichTextString rtS in reportText)
			{
				rtComp.Add(rtS);
			}
		}
		#endregion
	}
}
